---
title: "2：エコー"
---

import PlayIcon from '@material-ui/icons/PlayArrowSharp' 
import RestartIcon from '@material-ui/icons/ReplaySharp' 
import StopIcon from '@material-ui/icons/StopSharp'

ここまでで、 Pipy を使用した単純な「Hello World」サーバーを正しく実行できるようになりました。 このパートでは、サーバーが動的なコンテンツでレスポンスできるようにする方法を解説します。

## エコーサーバー

最初に、サーバーがポート 8081 で指定した文字を返すようにしてみましょう。

``` js
  pipy()

  .listen(8080)
    .serveHTTP(
      new Message('Hi, there!\n')
    )

+ .listen(8081)
+   .serveHTTP(
+     msg => new Message(msg.body)
+   )
```

ご覧の通り、ここでは新しいプログラムを作っていません。前回のプログラムに、もう一つのポートパイプラインを追加して拡張しているだけです。

新しいパイプラインはポート8081をリッスンし、前回と同じ serverHTTP フィルターがあります。但し、前回と違うのは、 serveHTTP に与える構成パラメータが [_Message_](/reference/api/Message) オブジェクトではなく、関数になっています。

この関数が動的なコンテンツを扱う秘訣です。

### コードの説明

最初のパイプラインでは、new Message() は Pipy の起動時に1回だけ評価されます。 つまり、 Pipy が後に受信するリクエスト数に関係なく、 Message オブジェクトは1つに固定されます。 したがって、 Pipy からのレスポンスは変わることがありません。

2番目のパイプラインでは、 msg => new Message() も Pipy の起動時に1回だけ評価されますが、最初のパイプラインとは違って、この評価は Message オブジェクトではなく関数です。 実行時には、関数がリクエストごとに1回評価されることになり、毎回異なる Message をレスポンスとして取得することができます。

この関数には入力変数のmsgがあり、これは [_Message_](/reference/api/Message) オブジェクトの形式でラップされたHTTPリクエストです。 これはレスポンスとして _Message_ も出力します。 ここでは、単にリクエストと同じ内容文の新しい _Message_ を寄せ集めているだけです。 単純な「エコーサーバー」としてはこれで十分でしょう。

### テストしてみる

テストする前に、忘れずに変更を保存してください。 この時点で Pipy がまだ古いバージョンのコードを実行している場合は、次のどちらかを行います。

1. ボタン <StopIcon/> をクリックして古いバージョンを停止し、その後ボタン <PlayIcon/> をクリックして新しいバージョンを実行するまたは。

2. ボタン <RestartIcon/> をクリックして新しいバージョンを直接再スタートさせる。

再度、コマンドラインから curl でテストします。

``` sh
curl localhost:8081 -d 'hello'
```

次のような結果になります。

```
hello
```

できましたね！

## もっとエコーなサーバー

では、この「オウム返し」以上の事をしてみましょう。クライアント側が何を言ったかだけではなく、クライアントが何処にいるかを返してみます。


``` js
  pipy()

  .listen(8080)
    .serveHTTP(
      new Message('Hi, there!\n')
    )

  .listen(8081)
    .serveHTTP(
      msg => new Message(msg.body)
    )

+ .listen(8082)
+   .serveHTTP(
+     msg => new Message(
+       `You are requesting ${msg.head.path} from ${__inbound.remoteAddress}\n`
+     )
+   )
```

再び、既存のコードに追加していきます。ここでは新しいパイプラインをポート 8082 でリッスンします。同じく _serveHTTP_ フィルターを使いますが関数が変わっています。

### コードの説明

今回は、 JavaScript の [_template string_](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Template_literals) を使用して動的に構成されたテキストコンテンツを返します。 このテンプレート文字列には、次の2つの動的な部分があります:

* `msg.head.path` は HTTP リクエストで要求された URI
* `__inbound.remoteAddress` はクライアントの IP アドレス

変数 `__inbound` は、ビルトインのグローバルオブジェクトにある、現在のインバウンド接続に関するアドレス/ポート情報です。これはグローバル変数ですが、同時インバウンド接続を扱う同時進行のパイプライン間で異なる値を持ちます。

これは、プログラム全体で状態が共有されるグローバル変数に慣れている人には違和感があるかもしれません。 より詳細な説明については、 [Context](/intro/concepts#コンテキスト) の _Concepts_ を参照してください。

### テストしてみる

ターミナルから以下を入力すると:

``` sh
curl localhost:8082/hello
```

以下が返されます。

```
You are requesting /hello from ::1
```

「::1」とは、 IPv6 形式での _localhost_ のアドレスです。

## まとめ

このパートでは、 Pipy プログラムからのレスポンスで動的なコンテンツを作成する方法を解説しました。 また、 Pipy で変数がどのように機能するかについても軽く触れました。

### 要点

1. フィルターパラメーターは一度だけ評価されるため、実行時に「_static_」な値になります。 それを「_dynamic_」にするには、動的な値を出力する関数にする必要があります。

2. グローバル変数は、同時に進行するパイプライン間では分離された状態にあります。 ビルトインのグローバル変数の1つに `__inbound` があり、現在の着信接続に関するアドレス/ポート情報を持っています。

### 次のパートの内容

Pipy は、アドホックなサーバーをすばやく立ち上げるのに便利なことは分かったと思いますが、Pipyの本来の目的はそれだけではありません。 Pipy は主にネットワークプロキシとしても使われます。 次のパートではそれを解説します。